package com.chenxin.wms.process.inbound.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chenxin.common.annotation.WmsLogs;
import com.chenxin.common.constant.WmsConstants;
import com.chenxin.common.core.domain.ProcResult;
import com.chenxin.common.enums.WmsSpuStatus;
import com.chenxin.common.enums.wms.*;
import com.chenxin.common.exception.wms.WmsException;
import com.chenxin.common.utils.StringUtils;
import com.chenxin.wms.domain.IbDetailEntity;
import com.chenxin.wms.domain.IbMasterEntity;
import com.chenxin.wms.domain.StockEntity;
import com.chenxin.wms.domain.TaskEntity;
import com.chenxin.wms.domain.dto.FinishedGoodsRegisterParams;
import com.chenxin.wms.domain.po.SpuInfo;
import com.chenxin.wms.domain.po.StationInfo;
import com.chenxin.wms.mapper.*;
import com.chenxin.wms.process.inbound.IProcFinishedGoodsRegister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
public class ProcFinishedGoodsRegister implements IProcFinishedGoodsRegister {

    @Autowired
    private IbMasterMapper ibMasterMapper;
    @Autowired
    private IbDetailMapper ibDetailMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private StationMapper stationMapper;

    @WmsLogs(name = "成品收货登记")
    @Transactional
    @Override
    public ProcResult call(FinishedGoodsRegisterParams dto) {
        if (dto == null) {
            return ProcResult.error("fg_receive_000", "请求参数不能为空");
        }

        // 0.获取相关参数
        Long ibDetailId = dto.getIbDetailId();
        String stationNo = dto.getStationNo();
        String contNo = dto.getContNo();
        String lotNo = dto.getLotNo();
        BigDecimal inQty = dto.getInQty();
        Long creator = dto.getCreator();
        Date workDate = new Date();

        // 1.参数校验
        ProcResult validResult = validateParameters(ibDetailId, stationNo, contNo, inQty);
        if (!validResult.getCode().equals("0")) {
            return validResult;
        }

        // 2.根据明细ID获取入库单明细信息
        IbDetailEntity detailInfo = ibDetailMapper.selectById(ibDetailId);
        if (detailInfo == null) {
            return ProcResult.error("fg_receive_005", "明细ID【" + ibDetailId + "】不存在");
        }
        // 获取主单的单据信息
        IbMasterEntity ibMaster = ibMasterMapper.selectById(detailInfo.getIbMasterId());
        if (ibMaster == null) {
            return ProcResult.error("fg_receive_005", "主单ID【" + detailInfo.getIbMasterId() + "】不存在");
        }

        // 2.1 根据入库明细单查询主单信息是成品入库单
        String ibMasterType = ibMaster.getIbMasterType();
        if (ibMasterType == null || !ibMasterType.equals(IbMasterType.IN_FG.getCode())) {
            return ProcResult.error("fg_receive_006", "明细ID【" + ibDetailId + "】单据类型【" + ibMasterType + "】非成品入库单，不允许收货");
        }

        // 3.根据明细信息获取其他所需信息
        String spuNo = detailInfo.getSpuNo();
        Integer ibDetailStatus = detailInfo.getIbDetailStatus();

        // 3.3.判断明细单据状态是否允许继续收货状态
        if (ibDetailStatus > IbDetailStatus.EXEC.getCode()) {
            return ProcResult.error("fg_receive_009", "明细ID【" + ibDetailId + "】当前状态【" + ibDetailStatus + "】已收货完成");
        }

        BigDecimal planQty = detailInfo.getIbPlanQty();
        BigDecimal ibActualQty = detailInfo.getIbActualQty();
        // 可收数量
        BigDecimal remainQty = planQty.subtract(ibActualQty);
        // 3.4判断收货数量是否大于入库单明细剩余数量（计划-实际）
        if (inQty.compareTo(remainQty) > 0) {
            return ProcResult.error("fg_receive_010", "收货数量【" + inQty + "】大于明细ID【" + ibDetailId + "】剩余可收数量【" +
                    remainQty + "】，不允许收货");
        }

        // 3.1.判断物料是否维护
        SpuInfo spuInfo = spuMapper.selectSpuInfoByNo(spuNo);
        if (spuInfo == null) {
            return ProcResult.error("fg_receive_007", "明细ID【" + ibDetailId + "】中物料【" + spuNo + "】未维护，不允许收货");
        }
        Long zoneIdBySpu = spuInfo.getZoneId();

        // 3.2.废弃物料或者未维护物料不允许收货
        if (spuInfo.getDelFlag().equals(WmsSpuStatus.DELETE.getCode()) || String.valueOf(spuInfo.getSpuStatus()).equals(WmsSpuStatus.DISABLE.getCode())) {
            return ProcResult.error("fg_receive_008", "明细ID【" + ibDetailId + "】中物料【" + spuNo + "】已停用或已废弃，不允许收货");
        }

        // 3.3.判断物料默认上架库区是否维护
        if (zoneIdBySpu == null) {
            return ProcResult.error("wip_register_005", "明细ID【" + ibDetailId + "】中物料【" + spuNo + "】未配维护上架区域");
        }
        // 4.根据收货站台获取库区信息
        StationInfo stationInfo = stationMapper.selectStationInfoByNo(stationNo);
        if (stationInfo == null) {
            return ProcResult.error("fg_receive_011", "明细ID【" + ibDetailId + "】收货站台【" + stationNo + "】未配置");
        }
        Long zoneIdByStation = stationInfo.getZoneId();
        String zoneType = stationInfo.getZoneType();
        String stationType = stationInfo.getStationType();
        // 站台对应的位置信息
        String locationByStation = stationInfo.getLocationNo();
        // 4.1判断站台是否可用且为入库站台
        if (!WmsConstants.STN_TYPE_SI.equals(stationType)) {
            return ProcResult.error("fg_receive_012", "明细ID【" + ibDetailId + "】收货站台【" + stationNo + "】非入库站台");
        }

        // 4.2.判断物料的默认上架库区与站台所属库区是否一致,不一致不允许收货
        if (!zoneIdBySpu.equals(zoneIdByStation)) {
            return ProcResult.error("fg_receive_013", "物料【" + spuNo + "】的上架库区【" + zoneIdBySpu +
                    "】与收货站台【" + stationNo + "】所属库区不一致");
        }

        // 判断LPN是否已存在其他位置的库存
        QueryWrapper<StockEntity> existStockQW = new QueryWrapper<>();
        existStockQW.lambda().eq(StockEntity::getContNo, contNo);
        List<StockEntity> existStockList = stockMapper.selectList(existStockQW);
        if (existStockList != null && existStockList.size() > 0) {
            for (StockEntity stock : existStockList) {
                // 检查所有库存的所在位置是否与当前收货位置一致
                if (!locationByStation.equals(stock.getLocationNo())) {
                    return ProcResult.error("fg_receive_015", "明细ID【" + ibDetailId + "】所用托盘【" + contNo + "】已存在其他位置的库存");
                }
            }
        }

        // 5.判断托盘是否存在其他类型的任务
        QueryWrapper<TaskEntity> existTaskQW = new QueryWrapper<>();
        existTaskQW.lambda().eq(TaskEntity::getFromContNo, contNo)
                .le(TaskEntity::getTaskStatus, TaskStatus.DONE.getCode());
        List<TaskEntity> existTaskList = taskMapper.selectList(existTaskQW);
        if (existTaskList != null && existTaskList.size() > 0) {
            for (TaskEntity task : existTaskList) {
                if (!task.getTaskSubType().equals(TaskType.SUB_GOODS_IN.getCode())) {
                    return ProcResult.error("fg_receive_014", "明细ID【" + ibDetailId + "】所用托盘【" + contNo + "】已存在其他场景任务");
                }
                if (!locationByStation.equals(task.getFromPosition())) {
                    return ProcResult.error("fg_receive_016", "明细ID【" + ibDetailId + "】所用托盘【" + contNo + "】已用于其他区域收货");
                }
            }
        }

        // 8.处理库存记录 - 每次登记都创建新的库存记录
        StockEntity fgStock = new StockEntity();
        fgStock.setContNo(contNo);
        fgStock.setLocationNo(locationByStation);
        fgStock.setSpuNo(spuNo);
        fgStock.setStockQty(inQty);
        fgStock.setQualityStatus(spuInfo.getIsQuality().equals("0") ? StockQuality.QB.getCode() : StockQuality.QA.getCode());
        fgStock.setIbDetailId(ibDetailId);
        fgStock.setSupplierNo(ibMaster.getSupplierNo());
        fgStock.setCreator(creator);
        fgStock.setCreateDate(workDate);

        // 写入库存
        stockMapper.insert(fgStock);

        // 9.每次登记都创建新的任务记录
        TaskEntity fgTask = new TaskEntity();
        fgTask.setTaskType(TaskType.RECEIVE_IN.getCode());
        fgTask.setTaskSubType(TaskType.SUB_GOODS_IN.getCode());
        fgTask.setTaskStatus(TaskStatus.INIT.getCode());
        fgTask.setFromContNo(contNo);
        // 10.1存放物料信息
        fgTask.setSpuNo(spuNo);
        fgTask.setLotNo(lotNo);
        fgTask.setPlanQty(inQty);
        fgTask.setMasterNo(detailInfo.getIbMasterNo());
        fgTask.setMasterId(detailInfo.getIbMasterId());
        fgTask.setDetailId(ibDetailId);
        //10.2 货位位置信息
        fgTask.setFromPosition(locationByStation);
        fgTask.setCurPosition(locationByStation);
        // 收货登记目标位置暂不填写
        fgTask.setToPosition("");
        fgTask.setStationNo(stationNo);
        // 写入关联库存ID
        fgTask.setStockId(fgStock.getStockId());
        fgTask.setCreator(creator);
        fgTask.setCreateDate(workDate);
        // 10.3写入任务
        taskMapper.insert(fgTask);

        // 11.1.判断单据是否收货完成（计划收货数量=实际收货数量）
        if (inQty.compareTo(remainQty) < 0) {
            detailInfo.setIbDetailStatus(IbDetailStatus.EXEC.getCode());
        } else {
            detailInfo.setIbDetailStatus(IbDetailStatus.DONE.getCode());
        }

        // 11.2.更新入库明细单据信息（将收货数量累加到实际数量上）
        detailInfo.setIbActualQty(detailInfo.getIbActualQty().add(inQty));
        UpdateWrapper<IbDetailEntity> detailUW = new UpdateWrapper<>();
        detailUW.lambda().set(IbDetailEntity::getIbActualQty, detailInfo.getIbActualQty())
                .set(IbDetailEntity::getIbDetailStatus, detailInfo.getIbDetailStatus())
                .set(IbDetailEntity::getLotNo, lotNo)
                .set(IbDetailEntity::getUpdater, creator)
                .set(IbDetailEntity::getUpdateDate, workDate)
                .set(IbDetailEntity::getVersion, detailInfo.getVersion() + 1)
                .eq(IbDetailEntity::getIbDetailId, ibDetailId)
                .eq(IbDetailEntity::getVersion, detailInfo.getVersion());
        int rowByUpdateDetail = ibDetailMapper.update(detailUW);
        if (rowByUpdateDetail == 0) {
            throw new WmsException("wip_register_015", "入库登记失败!更新入库明细【" + ibDetailId + "】异常");
        }

        // 11.3.更新主单状态
        //ibMasterStatusProcess.statusUpdateByMasterId(ibMaster.getIbMasterId(), creator);
        return ProcResult.success("成品收货成功，明细ID【" + ibDetailId + "】，托盘【" + contNo + "】物料【" +
                spuNo + "】收货数量【" + inQty + "】，收货站台【" + stationNo + "】");
    }

    /* 参数填写校验  */
    private ProcResult validateParameters(Long ibDetailId, String stationNo, String contNo, BigDecimal inQty) {
        if (StringUtils.isNull(ibDetailId)) {
            return ProcResult.error("fg_receive_001", "入库明细ID不能为空");
        }
        if (StringUtils.isNull(stationNo)) {
            return ProcResult.error("fg_receive_002", "收货站台不能为空");
        }
        if (StringUtils.isNull(contNo)) {
            return ProcResult.error("fg_receive_003", "LPN不能为空");
        }
        if (inQty.compareTo(BigDecimal.ZERO) <= 0) {
            return ProcResult.error("fg_receive_004", "收货数量不能小于等于0");
        }
        return ProcResult.success("必填校验");
    }
}
